﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading.Tasks;

namespace asoptions
{
    public partial class MainWindow : Form
    {
        private ASInterface asint;
        private Tagger tagger;
        private MusicLibrary lib;
        private bool fastConnect;
        private bool clearTmpDir;
        private OpenFileDialog ofd;
        private List<TreeNode> checkedNodes;
        public string[] exts = { "*.mp3", "*.m4a", "*.ogg", "*.wma" };

        public MainWindow()
        {
            InitializeComponent();
            this.FormClosing += new FormClosingEventHandler(this.MainWindow_FormClosing);

            fastConnect = Properties.Settings.Default.fastStart;
            clearTmpDir = Properties.Settings.Default.clearTmp;
            if (clearTmpDir)
                deleteTmp();

            tagger = new Tagger(this);
            asint = new ASInterface(this);
            lib = new MusicLibrary(this);

            ofd = new OpenFileDialog();
            ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
            ofd.Filter = "Audio files (*.mp3;*.m4a;*.ogg;*.wma)|*.mp3;*.m4a;*.ogg;*.wma";
            ofd.FilterIndex = 1;
            ofd.RestoreDirectory = true;
            ofd.Multiselect = true;

            checkedNodes = new List<TreeNode>();

            defaultCharComboBox.SelectedIndex = Properties.Settings.Default.defaultChar;
            charSelectComboBox.SelectedIndex = Properties.Settings.Default.defaultChar;

            charComboBox.SelectedIndex = 0;
            monoGreyComboBox.SelectedIndex = 2;
            cameraComboBox.SelectedIndex = 0;
            buildTmpFolderTreeView();
            tmpFolderFileSystemWatcher.Path = tagger.tmpFolderPath;
            tmpFolderFileSystemWatcher.Filter = "";
            tmpFolderFileSystemWatcher.EnableRaisingEvents = true;
            backgroundWorker1.RunWorkerAsync();
        }

        private delegate void Log(string str, MessageType type);
        /// <summary>
        /// Append a string to the log.
        /// </summary>
        /// <param name="str">String to append to the log</param>
        public void addToLog(string str, MessageType type)
        {
            if (logTextBox.InvokeRequired)
            {
                logTextBox.Invoke(new Log(addToLog), new object[] { str, type });
            }
            else
            {
                switch (type)
                {
                    case MessageType.Info:
                        logTextBox.SelectionColor = Color.Black;
                        break;
                    case MessageType.Error:
                        logTextBox.SelectionColor = Color.Red;
                        break;
                    case MessageType.Warning:
                        logTextBox.SelectionColor = Color.OrangeRed;
                        break;
                    case MessageType.FromAS:
                        logTextBox.SelectionColor = Color.DarkBlue;
                        break;
                    case MessageType.ToAS:
                        logTextBox.SelectionColor = Color.DarkOliveGreen;
                        break;
                }
                logTextBox.AppendText("\n" + str);
                logTextBox.SelectionColor = Color.Black;
            }
        }

        private void logMessageEvent(LogMessageEventArgs e)
        {
            addToLog(e.message, e.type);
        }

        private void deleteTmp()
        {
            try
            {
                Directory.Delete(tagger.tmpFolderPath, true);
            }
            catch
            {
            }
        }

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (clearTmpDir)
            {
                deleteTmp();
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == ASInterface.WM_COPYDATA)
            {
                ASInterface.COPYDATASTRUCT str = new ASInterface.COPYDATASTRUCT();
                Type type = str.GetType();
                str = (ASInterface.COPYDATASTRUCT)m.GetLParam(type);
                addToLog(str.lpData.Substring(0, str.cbData), MessageType.FromAS);

                if (str.lpData.Contains("successfullyregistered") ||
                    str.lpData.Contains("successfullyquickstartregistered"))
                    ASInterface.state = ASInterface.state | CurrentState.Connected;
                else if (str.lpData.Contains("asreport songcomplete"))
                {
                    ASInterface.state = ASInterface.state & ~(CurrentState.InSong);
                    if (playlistControl.playingFromPlaylist)
                        playlistControl.nextSong();
                }
                else if (str.lpData.Contains("asreport nowplayingartistname"))
                    ASInterface.state = ASInterface.state | CurrentState.InSong;
                else if (str.lpData.Contains("asreport oncharacterscreen") && playlistControl.playingFromPlaylist)
                {
                    ASInterface.state = ASInterface.state & ~(CurrentState.InSong);

                    playlistControl.playingFromPlaylist = false;
                }
            }

            base.WndProc(ref m);
        }

        private void launchToolStripButton_Click(object sender, EventArgs e)
        {
            addToLog("[Launching Audiosurf]", MessageType.Info);
            System.Diagnostics.Process audproc = new System.Diagnostics.Process();
            audproc.StartInfo.FileName = "steam://run/12900";
            audproc.Start();
            launchToolStripButton.Enabled = false;
        }

        private void statusTimer_Tick(object sender, EventArgs e)
        {
            bool running = asint.isRunning();
            if (!running)
            {
                statusToolStripTextBox.Text = "Not Connected";
                statusToolStripTextBox.BackColor = System.Drawing.Color.Firebrick;
                launchToolStripButton.Enabled = true;
                asint.hwnd = 0;
                ASInterface.state = CurrentState.Closed;
            }
            else if (running &&
                    (ASInterface.state & CurrentState.Connected) != CurrentState.Connected)
            {
                statusToolStripTextBox.Text = "Connecting";
                bool good = false;
                if (fastConnect)
                    good = asint.connectFast(this.Text);
                else
                    good = asint.connect(this.Text);
                if (good)
                {
                    //statusToolStripTextBox.Text = "Connected";
                    //statusToolStripTextBox.BackColor = System.Drawing.Color.DarkGreen;
                    launchToolStripButton.Enabled = false;
                }
            }
            else if ((ASInterface.state & CurrentState.Connected) == CurrentState.Connected)
            {
                statusToolStripTextBox.Text = "Connected";
                statusToolStripTextBox.BackColor = System.Drawing.Color.DarkGreen;
                launchToolStripButton.Enabled = false;
            }
        }

        private void tmpFolderFileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            string ex = e.FullPath.Substring(e.FullPath.LastIndexOf('.'));
            if (ex.Equals(".mp3") || ex.Equals(".m4a") || ex.Equals(".wma") || ex.Equals(".ogg"))
            {
                FileInfo file = new FileInfo(e.FullPath);
                updateNode(file);
            }
        }

        #region folder treeviews

        /// <summary>
        /// Builds the TreeView for the tmp folder.
        /// TODO: separate thread? probably not as not many files will ever be here
        /// </summary>
        private void buildTmpFolderTreeView()
        {
            DirectoryInfo dir = new DirectoryInfo(tagger.tmpFolderPath);

            tmpFolderTreeView.BeginUpdate();
            foreach (var file in exts.AsParallel().SelectMany(searchPattern => dir.EnumerateFiles(searchPattern)))
            {
                tmpFolderTreeView.Nodes.Add(MusicLibrary.createMusicNode(file));
            }
            tmpFolderTreeView.EndUpdate();
        }

        /// <summary>
        /// Updates or creates a node in tmpFolderTreeView. Meant to be called when a file is
        /// added/modified in the tmp folder.
        /// </summary>
        /// <param name="file">File associated with the node to create/update</param>
        private void updateNode(FileInfo file)
        {
            TreeNode node = MusicLibrary.createMusicNode(file);
            node.ExpandAll();
            int index = tmpFolderTreeView.Nodes.IndexOfKey(file.FullName);
            tmpFolderTreeView.BeginUpdate();
            if (index < 0)
                tmpFolderTreeView.Nodes.Add(node);
            else
            {
                tmpFolderTreeView.Nodes[index].Remove();
                tmpFolderTreeView.Nodes.Insert(index, node);
            }
            tmpFolderTreeView.EndUpdate();
        }

        /// <summary>
        /// Build the music folder's TreeView. Should only be called in its own thread as it's really freaking slow.
        /// </summary>
        private void buildMusicFolderTreeView()
        {
            lib.createLibrary(libFoldersListBox.Items);
            foreach (var n in lib.getRoots())
            {
                // have to add the node in the gui thread...
                musicFolderTreeView.Invoke(new Add(addNode), new object[] { n });
            }
        }

        private delegate void Add(TreeNode n);
        /// <summary>
        /// Add a node to musicFolderTreeView
        /// </summary>
        /// <param name="n"></param>
        private void addNode(TreeNode n)
        {
            musicFolderTreeView.BeginUpdate();
            n.Expand();
            musicFolderTreeView.Nodes.Add(n);
            musicFolderTreeView.EndUpdate();
        }

        /// <summary>
        /// Check all children of a node recursively
        /// </summary>
        /// <param name="tnode">TreeNode whose children will be checked/unchecked</param>
        /// <param name="isChecked">True to check, false to uncheck</param>
        private void checkNodeChildren(TreeNode tnode, bool isChecked)
        {
            foreach (TreeNode node in tnode.Nodes)
            {
                node.Checked = isChecked;
                if (isChecked && (NodeType)node.Tag == NodeType.Song && !tagger.editingSong(node.Text))
                    checkedNodes.Add(node);
                else if (!isChecked && (NodeType)node.Tag == NodeType.Song)
                    checkedNodes.Remove(node);
                if (node.Nodes.Count > 0)
                    checkNodeChildren(node, isChecked);
            }
        }

        private void musicFolderTreeView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Action != TreeViewAction.Unknown)
            {
                if ((NodeType)e.Node.Tag == NodeType.Song && !tagger.editingSong(e.Node.Text) && e.Node.Checked)
                    checkedNodes.Add(e.Node);
                else if ((NodeType)e.Node.Tag == NodeType.Song && !e.Node.Checked)
                    checkedNodes.Remove(e.Node);
                if (e.Node.Nodes.Count > 0)
                    checkNodeChildren(e.Node, e.Node.Checked);
            }
        }

        // TODO: adding songs by clicking this button is very inefficient. It works fine for small numbers, but
        // can get slow with too many. Should either make it more efficient or run it in it's own thread (ugh).
        private void musicFolderEditButton_Click(object sender, EventArgs e)
        {
            foreach (var node in checkedNodes)
            {
                editSongTags(node.Name, node.Text);
            }
            checkedNodes.Clear();
            foreach (TreeNode node in musicFolderTreeView.Nodes)
            {
                node.Checked = false;
                checkNodeChildren(node, false);
            }
        }

        private void toPLfromLibButton_Click(object sender, EventArgs e)
        {
            foreach (var node in checkedNodes)
            {
                //plist.addToPlaylist(node.Name, node.Text);
                playlistControl.addToPlaylist(node.Name, node.Text);
            }
            checkedNodes.Clear();
            foreach (TreeNode node in musicFolderTreeView.Nodes)
            {
                node.Checked = false;
                checkNodeChildren(node, false);
            }
            //updatePlaylist();
            //userControl11.updatePlaylist();
        }

        private delegate void libraryRefreshEnabled(bool b);
        /// <summary>
        /// Used for enabling/disabling appropriate controls when the library is being refreshed.
        /// </summary>
        /// <param name="b">True if controls should be enabled, false otherwise</param>
        public void libraryRefreshButtonEnabled(bool b)
        {
            if (libraryRefreshButton.InvokeRequired)
                libraryRefreshButton.Invoke(new libraryRefreshEnabled(libraryRefreshButtonEnabled), new object[] { b });
            else
            {
                libraryRefreshButton.Enabled = b;
                libAddButton.Enabled = b;
                libRemoveButton.Enabled = b;
                libFoldersListBox.Enabled = b;
                if (b)
                    libraryRefreshButton.BackgroundImage = Properties.Resources.refreshImage;
                else
                    libraryRefreshButton.BackgroundImage = Properties.Resources.refreshImageGrey;
            }
        }

        private void libraryRefreshButton_Click(object sender, EventArgs e)
        {
            File.Delete(lib.xmlPath);
            musicFolderTreeView.Nodes.Clear();
            backgroundWorker1.RunWorkerAsync();
        }

        #endregion

        #region tag options tab

        private delegate void fnlbupdate(Song s);
        public void fileNameListBox_Remove(Song s)
        {
            if (fileNameListBox.InvokeRequired)
            {
                fileNameListBox.Invoke(new fnlbupdate(fileNameListBox_Remove), new object[] { s });
            }
            else
            {
                fileNameListBox.Items.Remove(s);
                editStateChanged();
            }
        }

        public void fileNameListBox_Add(Song s)
        {
            if (fileNameListBox.InvokeRequired)
            {
                fileNameListBox.Invoke(new fnlbupdate(fileNameListBox_Add), new object[] { s });
            }
            else
            {
                fileNameListBox.Items.Add(s);
                editStateChanged();
            }
        }

        // TODO: decrapify
        private void removeButton_Click(object sender, EventArgs e)
        {
            var selected = fileNameListBox.SelectedItems;
            List<Song> toRemove = new List<Song>();
            for (int k = 0; k < selected.Count; k++)
            {
                toRemove.Add((Song)selected[k]);
            }
            foreach (var song in toRemove)
            {
                tagger.removeSong(song);
                fileNameListBox_Remove(song);
            }
        }

        private void browseButton_Click(object sender, EventArgs e)
        {
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                editSongTags(ofd.FileNames, ofd.SafeFileNames);
            }
        }

        /// <summary>
        /// Checks if the user is editing files and enables/disables appropriate components.
        /// Should be called every time the user adds or removes a file.
        /// </summary>
        private void editStateChanged()
        {
            if (fileNameListBox.Items.Count > 0)
            {
                tagOptionsGroupBox.Enabled = true;
            }
            else
            {
                tagOptionsGroupBox.Enabled = false;
            }
        }

        private void fileNameListBox_SelectedValueChanged(object sender, EventArgs e)
        {
            if (fileNameListBox.SelectedItems.Count > 0)
            {
                playGroupBox.Enabled = true;
                removeButton.Enabled = true;
            }
            else
            {
                playGroupBox.Enabled = false;
                removeButton.Enabled = false;
            }
        }

        /// <summary>
        /// Sets up a single file for editing
        /// </summary>
        /// <param name="filename">Full path of the file</param>
        /// <param name="safeFileName">File name (excluding path)</param>
        private void editSongTags(string filename, string safeFileName)
        {
            string[] fn = { filename };
            string[] sfn = { safeFileName };
            editSongTags(fn, sfn);
        }

        /// <summary>
        /// Sets up multiple files for editing.
        /// </summary>
        /// <param name="fileNames">Full path of the files</param>
        /// <param name="safeFileNames">File names (excluding path)</param>
        private void editSongTags(string[] fileNames, string[] safeFileNames)
        {
            fileNameListBox.BeginUpdate();
            for (int k = 0; k < fileNames.Length; k++)
            {
                try
                {
                    FileStream file = new FileStream(fileNames[k], FileMode.Open, FileAccess.Read);
                    string tmppath = System.IO.Path.Combine(tagger.tmpFolderPath, safeFileNames[k]);
                    FileStream tmpfile = new FileStream(tmppath, FileMode.Create);
                    file.CopyTo(tmpfile);
                    tmpfile.Close();
                    file.Close();
                    Song s = new Song(tmppath, safeFileNames[k]);
                    tagger.currentSong.AddLast(s);
                }
                catch (Exception ex)
                {
                    addToLog("Error: " + ex.Message, MessageType.Error);
                }
                fileNameListBox.Items.Add(tagger.currentSong.Last.Value);
            }
            fileNameListBox.EndUpdate();
            editStateChanged();
        }

        private void fourLanecheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (fourLanecheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.FourLane;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.FourLane);
        }

        private void saveTagButton_Click(object sender, EventArgs e)
        {
            tagger.saveCurrent();
        }

        private void noStealthBonusCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (noStealthBonusCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.NoStealthBonus;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.NoStealthBonus);
        }

        private void caterpCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (caterpCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.LongChains;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.LongChains);
        }

        private void invisCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (invisCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.InvGrid;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.InvGrid);
        }

        private void steepCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (steepCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.IncSpeed;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.IncSpeed);
        }

        private void portalCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (portalCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.Portal;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.Portal);
        }

        private void monoPtsCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            tagger.monoBasePts = (int)monoPtsNumericUpDown.Value;
            if (monoPtsCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.MonoBasePts;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.MonoBasePts);
        }

        private void matchSizeCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            tagger.minMatchSize = (int)matchSizeNumericUpDown.Value;
            if (matchSizeCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.MinMatchSize;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.MinMatchSize);
        }

        private void whitePerCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            tagger.perWhiteBlock = (int)whitePerNumericUpDown.Value;
            if (whitePerCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.PerWhiteBlock;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.PerWhiteBlock);
        }

        private void matchTicCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            tagger.matchTicks = (int)matchTicNumericUpDown.Value;
            if (matchTicCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.MatchTicks;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.MatchTicks);
        }

        private void rowCtCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            tagger.rowCount = (int)rowCtNumericUpDown.Value;
            if (rowCtCheckBox.Checked)
                tagger.currentOps = tagger.currentOps | TagOptions.RowCount;
            else
                tagger.currentOps = tagger.currentOps & ~(TagOptions.RowCount);
        }

        private void charComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (charComboBox.SelectedIndex)
            {
                case 1:
                    tagger.currentOps = tagger.currentOps | TagOptions.CharMonoRestr;
                    tagger.monoChar = " [as-monoonly]";
                    break;
                case 2:
                    tagger.currentOps = tagger.currentOps | TagOptions.CharMonoRestr;
                    tagger.monoChar = " [as-everybodymono]";
                    break;
                default:
                    tagger.currentOps = tagger.currentOps & ~(TagOptions.CharMonoRestr);
                    tagger.monoChar = "";
                    break;
            }
        }

        private void monoGreyComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (monoGreyComboBox.SelectedIndex)
            {
                case 0:
                    tagger.currentOps = tagger.currentOps | TagOptions.MonoGray;
                    tagger.monoGreys = " [as-nogrey]";
                    break;
                case 1:
                    tagger.currentOps = tagger.currentOps | TagOptions.MonoGray;
                    tagger.monoGreys = " [as-lessgrey]";
                    break;
                case 3:
                    tagger.currentOps = tagger.currentOps | TagOptions.MonoGray;
                    tagger.monoGreys = " [as-allgrey]";
                    break;
                default:
                    tagger.currentOps = tagger.currentOps & ~(TagOptions.MonoGray);
                    tagger.monoGreys = "";
                    break;
            }
        }

        private void cameraComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cameraComboBox.SelectedIndex)
            {
                case 1:
                    tagger.currentOps = tagger.currentOps | TagOptions.Camera;
                    tagger.cameraMode = " [as-swind]";
                    break;
                case 2:
                    tagger.currentOps = tagger.currentOps | TagOptions.Camera;
                    tagger.cameraMode = " [as-bankcam]";
                    break;
                case 3:
                    tagger.currentOps = tagger.currentOps | TagOptions.Camera;
                    tagger.cameraMode = " [as-first]";
                    break;
                default:
                    tagger.currentOps = tagger.currentOps & ~(TagOptions.Camera);
                    tagger.cameraMode = "";
                    break;
            }
        }

        private void playButton_Click(object sender, EventArgs e)
        {
            saveTagButton.PerformClick();
            Song songToPlay;
            if (fileNameListBox.SelectedItems.Count > 0)
                songToPlay = (Song)fileNameListBox.SelectedItems[0];
            else
                songToPlay = (Song)fileNameListBox.Items[0];
            asint.playSong(songToPlay.fullPath);
        }

        private void toPLfromOpButton_Click(object sender, EventArgs e)
        {
            saveTagButton.PerformClick();
            while (fileNameListBox.SelectedItems.Count > 0)
            {
                Song toAdd = (Song)fileNameListBox.SelectedItems[0];
                toAdd.aschar = asint.currentChar;
                playlistControl.addToPlaylist((Song)fileNameListBox.SelectedItems[0]);
                fileNameListBox_Remove((Song)fileNameListBox.SelectedItems[0]);
            }
        }

        private void rowCtNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            tagger.rowCount = (int)rowCtNumericUpDown.Value;
        }

        private void whitePerNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            tagger.perWhiteBlock = (int)whitePerNumericUpDown.Value;
        }

        private void matchTicNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            tagger.matchTicks = (int)matchTicNumericUpDown.Value;
        }

        private void matchSizeNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            tagger.minMatchSize = (int)matchSizeNumericUpDown.Value;
        }

        private void monoPtsNumericUpDown_ValueChanged(object sender, EventArgs e)
        {
            tagger.monoBasePts = (int)monoPtsNumericUpDown.Value;
        }
        
        private void charSelectComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (charSelectComboBox.SelectedIndex)
            {
                case 0:
                    asint.currentChar = Characters.mono;
                    break;
                case 1:
                    asint.currentChar = Characters.pointman;
                    break;
                case 2:
                    asint.currentChar = Characters.doublevision;
                    break;
                case 3:
                    asint.currentChar = Characters.monopro;
                    break;
                case 4:
                    asint.currentChar = Characters.vegas;
                    break;
                case 5:
                    asint.currentChar = Characters.eraser;
                    break;
                case 6:
                    asint.currentChar = Characters.pointmanpro;
                    break;
                case 7:
                    asint.currentChar = Characters.pusher;
                    break;
                case 8:
                    asint.currentChar = Characters.doublevisionpro;
                    break;
                case 9:
                    asint.currentChar = Characters.ninjamono;
                    break;
                case 10:
                    asint.currentChar = Characters.eraserelite;
                    break;
                case 11:
                    asint.currentChar = Characters.pointmanelite;
                    break;
                case 12:
                    asint.currentChar = Characters.pusherelite;
                    break;
                case 13:
                    asint.currentChar = Characters.doublevisionelite;
                    break;
                case 14:
                    asint.currentChar = Characters.freeride;
                    break;
            }
        }

        #endregion

        #region other options tab

        private void quickStartCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            fastConnect = quickStartCheckBox.Checked;
        }

        private void dirClearCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            clearTmpDir = dirClearCheckBox.Checked;
        }

        /// <summary>
        /// Add a folder to the library
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void libAddButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.ShowNewFolderButton = false;
            fbd.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
            DialogResult res = fbd.ShowDialog();
            if (res == DialogResult.OK)
            {
                if (tagger.tmpFolderPath.Contains(fbd.SelectedPath))
                    addToLog("Cannot add tmp folder to library", MessageType.Error);
                else if (!libFoldersListBox.Items.Contains(fbd.SelectedPath))
                {
                    libFoldersListBox.Items.Add(fbd.SelectedPath);
                    addToLog("Library settings changed. Refresh library to see changes", MessageType.Warning);
                }
                else
                    addToLog("Library already contains the selected path.", MessageType.Error);
            }
        }

        /// <summary>
        /// Remove folder(s) from the library
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void libRemoveButton_Click(object sender, EventArgs e)
        {
            while (libFoldersListBox.SelectedItems.Count > 0)
                libFoldersListBox.Items.Remove(libFoldersListBox.SelectedItems[0]);
            addToLog("Library settings changed. Refresh library to see changes", MessageType.Warning);
        }

        private delegate void libListBoxSetItems(List<string> paths);
        /// <summary>
        /// Set the folders that make up the music library. These paths are scaned recursively
        /// (elsewhere) for supported audio files.
        /// </summary>
        /// <param name="paths">List of folder paths.</param>
        public void libFoldersListBox_setItems(List<string> paths)
        {
            if (libFoldersListBox.InvokeRequired)
            {
                libFoldersListBox.Invoke(new libListBoxSetItems(libFoldersListBox_setItems), new object[] { paths });
            }
            else
            {
                libFoldersListBox.Items.Clear();
                foreach (var p in paths)
                    libFoldersListBox.Items.Add(p);
            }
        }

        #endregion

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                // We don't want to execute the following until the window has been created.
                // This is rarely a problem, but best to be safe.
                if (musicFolderTreeView.IsHandleCreated)
                {
                    libraryRefreshButtonEnabled(false);
                    buildMusicFolderTreeView();
                    break;
                }
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            libraryToolStripProgressBar.Value = e.ProgressPercentage;
        }

        private void playlistControl_PlaySong(string path, Characters ch)
        {
            asint.playSong(path, ch);
        }

        private void defaultCharComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            Properties.Settings.Default.defaultChar = defaultCharComboBox.SelectedIndex;
            Properties.Settings.Default.Save();
            charSelectComboBox.SelectedIndex = defaultCharComboBox.SelectedIndex;
        }
    }
}
